#include "stdafx.h"
#include "RtView.h"

#include "GlobalAppData.h"
#include "InputLayouts.h"
#include "HLSLEffect.h"
#include "Texture.h"

#include "Scene.h"
#include "SceneParser.h"
#include "Tracing.h"
#include "RenderTarget.h"

#include "Profiler.h"

using namespace rt;


void RtView::load()
{

	mIsUserInput = false;

	ID3D11Device * device = mcore::GlobalAppData::Instance.Device;

	// vertex buffer
	mgfx::VertexPositionTexture vertices[4];

	vertices[0].Position = XMFLOAT3(-1.0f, -1.0f, 0.5f);
	vertices[1].Position = XMFLOAT3(-1.0f,  1.0f, 0.5f);
	vertices[2].Position = XMFLOAT3( 1.0f, -1.0f, 0.5f);
	vertices[3].Position = XMFLOAT3( 1.0f,  1.0f, 0.5f);

	vertices[0].TextureCoord = XMFLOAT2(0.0f, 0.0f);
	vertices[1].TextureCoord = XMFLOAT2(0.0f, 1.0f);
	vertices[2].TextureCoord = XMFLOAT2(1.0f, 0.0f);
	vertices[3].TextureCoord = XMFLOAT2(1.0f, 1.0f);

	D3D11_BUFFER_DESC desc;
	desc.Usage = D3D11_USAGE_DEFAULT;
	desc.ByteWidth = sizeof(mgfx::VertexPositionTexture) * 4;
	desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	desc.CPUAccessFlags = 0;
	desc.MiscFlags = 0;

	D3D11_SUBRESOURCE_DATA data;
	data.pSysMem = vertices;
	data.SysMemPitch = 0;
	data.SysMemSlicePitch = 0;

	HR(device->CreateBuffer(&desc, &data, &mVertexBuffer));

	// index buffer
	short indices[6];

	indices[0] = 0;
	indices[1] = 1;
	indices[2] = 2;

	indices[3] = 1;
	indices[4] = 3;
	indices[5] = 2;

	desc.Usage = D3D11_USAGE_DEFAULT;
	desc.ByteWidth = sizeof(short) * 6;
	desc.BindFlags = D3D11_BIND_INDEX_BUFFER;

	data.pSysMem = indices;

	HR(device->CreateBuffer(&desc, &data, &mIndexBuffer));

	// effect
	mHLSLEffect = mgfx::HLSLEffect::createFromFile("RT.fx");

	SceneParser parser;
	mScene = parser.ParseFromFile("scene.txt");
	mCamera = &mScene->GetEditableCamera();

	mRenderWidth = parser.GetParsedWidth();
	mRenderHeight = parser.GetParsedHeight();
	mPreviewRenderWidth = mRenderWidth / 4;
	mPreviewRenderHeight = mRenderHeight / 4;

	mRenderTexture = mgfx::Texture::createEmpty("RT_RenderTexture", mRenderWidth, mRenderHeight);
	mPreviewRenderTexture = mgfx::Texture::createEmpty("RT_PreviewRenderTexture", mPreviewRenderWidth, mPreviewRenderHeight);

	mRenderTarget = new RT_Memory(mRenderWidth, mRenderHeight);
	mPreviewRenderTarget = new RT_Memory(mPreviewRenderWidth, mPreviewRenderHeight);

	

	mLoaded = true;
}

void RtView::unload()
{
	delete mScene;

	ReleaseCOM(mVertexBuffer);
	ReleaseCOM(mIndexBuffer);

	delete mRenderTarget;
	delete mPreviewRenderTarget;

	mLoaded = false;
}

void RtView::update(float dt)
{
	mTotalTime += dt;

	if(GetAsyncKeyState('A') & 0x8000) { mCamera->MoveLeft(20.0f*dt); mIsUserInput = true; }
	if(GetAsyncKeyState('D') & 0x8000) { mCamera->MoveRight(20.0f*dt); mIsUserInput = true; }
	if(GetAsyncKeyState('W') & 0x8000) { mCamera->MoveForward(20.0f*dt); mIsUserInput = true; }
	if(GetAsyncKeyState('S') & 0x8000) { mCamera->MoveBackward(20.0f*dt); mIsUserInput = true; }

	//if(GetAsyncKeyState('I') & 0x8000)      mLightPosition.z += 1.0f * dt;
	//if(GetAsyncKeyState('K') & 0x8000)      mLightPosition.z -= 1.0f * dt;
	//if(GetAsyncKeyState('J') & 0x8000)		mLightPosition.x += 1.0f * dt;
	//if(GetAsyncKeyState('L') & 0x8000)      mLightPosition.x -= 1.0f * dt;

}

void RtView::draw()
{
	ID3D11DeviceContext * context = mcore::GlobalAppData::Instance.DeviceContext;

	uint stride = sizeof(mgfx::VertexPositionTexture);
	uint offset = 0;

	context->IASetInputLayout(mgfx::VertexPositionTexture::InputLayout);
	context->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &offset);
	context->IASetIndexBuffer(mIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
	context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	if(mIsUserInput)
	{
		renderImage(*mPreviewRenderTarget, *mScene, mPreviewRenderWidth, mPreviewRenderHeight, true);
		mPreviewRenderTexture->setData((const byte*)mPreviewRenderTarget->GetPixels());
		mHLSLEffect->getEffect()->GetVariableByName("gTexture")->AsShaderResource()->SetResource(mPreviewRenderTexture->mResourceView);
	}
	else
	{
		renderImage(*mRenderTarget, *mScene, mRenderWidth, mRenderHeight, false);
		mRenderTexture->setData((const byte*)mRenderTarget->GetPixels());
		mHLSLEffect->getEffect()->GetVariableByName("gTexture")->AsShaderResource()->SetResource(mRenderTexture->mResourceView);
	}

	mHLSLEffect->getEffect()->GetVariableByName("gTime")->AsScalar()->SetFloat(mTotalTime);
	

	mIsUserInput = false;

	ID3DX11EffectTechnique * effectTech = mHLSLEffect->getEffect()->GetTechniqueByIndex(0);

	D3DX11_TECHNIQUE_DESC techDesc;
	HR(effectTech->GetDesc( &techDesc ));

	for(uint j = 0; j < techDesc.Passes; ++j)
	{
		ID3DX11EffectPass* pass = effectTech->GetPassByIndex(j);
		pass->Apply(0, context);
		context->DrawIndexed(6, 0, 0);
	}


}

bool RtView::onWindowMessage(UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch( msg )
	{
	case WM_MOUSEMOVE:
		{
			static bool firstTime = true;
			int mousePosX = LOWORD(lParam);
			int mousePosY = HIWORD(lParam);
			if(firstTime)
			{
				firstTime = false;
			}
			else
			{
				int diffY = mPrevMousePosY - mousePosY;
				int diffX = mPrevMousePosX - mousePosX;
				if(diffY != 0 || diffX != 0)
				{
					mCamera->RotateX(float(diffY));
					mCamera->RotateY(float(diffX));
					mIsUserInput = true;
				}
				
			}
			mPrevMousePosX = mousePosX;
			mPrevMousePosY = mousePosY;
			return true;
		}
		break;
	}
	return false;
}